<?php

/**
 * runningAhead.php, RunningAhead.com API Wrapper
 * 
 * This is a class written to allow easy use of the
 * RunningAhead.com SOAP API
 * @author Jon Gullidge <jon@gullidge.org>
 * @version 0.1.4
 * @package com.runningahead
 * @todo fix non-wsdl mode
 * @todo Encapsulate saveWorkout data
 * @todo Fix some 'hacks'
 */

Class RunningAhead {
	
	private $AppKey;		/* App Key */
	private $AppSecret;		/* App Secret */
	private $SessionKey;	/* Session Key retrieved from #BeginSession */
	private $Signature;		/* Signature retrieved from #AuthenticateApplication */
	
	private $Development; 	/* Sandbox used if 1 */
	private $Wsdl;			/* WDSL used if 1 */
	private $Location;

	private $SoapAction = 'http://Api.RunningAHEAD.com/'; /* For ease */
	
	private $Client;		/* SOAP Client Object */
	
	private $userPreferences; /* Stores user preferences */

	/**
	* Class Constructor - Begins authorisation protocols
	* @param String $appKey Application Key provided to access the API
	* @param String $appSecret Password provided to access the API
	* @param int $dev 1 for development mode, 0 for live mode (defaults to development mode)
	* @param int $wsdl 1 for WSDL mode, 0 for non-WSDL mode (currently forces WSDL mode)
	*/
	function __construct($appKey, $appSecret, $dev = 1, $wsdl = 1) {
		$this->AppKey = $appKey;
		$this->AppSecret = $appSecret;
		$this->Development = $dev;
		$this->Wsdl = 1; // Cannot use non-WDSL mode. Parameters form in a manner the server doesn't understand!
		
		$this->Location = 'http://api'.
						  ($this->Development ? '-sandbox' : '').
						  '.runningahead.com/api/api.asmx'.
						  ($this->Wsdl ? '?wsdl' : '');
						  
		$options = array();
		$options['location'] = $this->Location;
		$options['uri'] = 'http://Api.RunningAHEAD.com/';
		
		$this->Client = new SoapClient(($this->Wsdl ? $this->Location : NULL), $options); 

		/* #BeginSession */
		$soapCall = 'BeginSession';
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array('appKey' => $this->AppKey)),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
										   );

		If (isset($return->BeginSessionResult)) {
			$return = $return->BeginSessionResult;
			
			if (!$return->Code)
				$this->SessionKey = str_replace('-', '', $return->Data->SessionKey);
			else
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
				
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		/* #AuthenticateApplication */
		$soapCall = 'AuthenticateApplication';
		
		$this->Signature = $this->AppSecret.$this->SessionKey.$this->AppKey;
		$this->Signature = md5($this->Signature);
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'signature' => $this->Signature
																		)
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);

		If (isset($return->AuthenticateApplicationResult)) {
			$return = $return->AuthenticateApplicationResult;
			if (!$return->Code) {
				// Nothing, success! *Reserved for future use*
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
	}

	/**
	* Class Deconstructor - Terminates session
	* @ignore
	*/
	function __destruct() {
		/* #EndSession */
		$return = $this->Client->__soapCall('EndSession',
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.'EndSession')
											);
	}

	private function throwError($code, $call) {
		if ($code == 0)
			return;
			
		$error = $call.' ['.$code.'] - ';
		
		switch ($code) {
			case (10):
				$error .= 'An unknown error has occured.';
				break;
			case (11):
				$error .= 'An unknown database error has occured.';
				break;
			case (13):
				$error .= 'The requested service is unavailable.';
				break;
			case (30):
				$error .= 'The application has not authenticated.';
				break;
			case(31):
				$error .= 'The application has insufficient priveleges. (Please contact a runningahead administrator)';
				break;
			case (100):
				$error .= 'You have not acquired a session key.';
				break;
			case (101):
				$error .= 'Your application is denied access to the API.';
				break;
			case (102):
				$error .= 'AppKey is either missing or invalid.';
				break;
			case (103):
				$error .= 'Your signature is invalid.';
				break;
			case (104):
				$error .= 'Your session key is invalid.';
				break;
			case (105):
				$error .= 'The user specified cannot be found.';
				break;
			case (106):
				$error .= 'One or more of the parameters is invalid or missing.';
				break;
			case (107):
				$error .= 'The data type specified is not supported.';
				break;
			case (108):
				$error .= 'The data format is invalid.';
				break;
			case (109):
				$error .= 'The data encoding is invalid.';
				break;
			case (110):
				$error .= 'The activity type is invalid.';
				break;
			case (111):
				$error .= 'The date range is invalid.';
				break;
			case (112):
				$error .= 'The data field is missing or invalid.';
				break;
			case (113):
				$error .= 'The workout ID is missing or invalid.';
				break;
			case (114):
				$error .= 'The date is missing or invalid.';
				break;
			case (115):
				$error .= 'The event type ID is missing or invalid';
				break;
			case (116):
				$error .= 'The event sub type ID is missing or invalid';
				break;
			case (117):
				$error .= 'The interval set name is invalid or missing.';
				break;
			case (118):
				$error .= 'The distance is missing or invalid.';
				break;
			case (119):
				$error .= 'The distance unit missing or invalid.';
				break;
			case (120):
				$error .= 'The weight unit is missing or invalid.';
				break;
			case (121):
				$error .= 'The rest, average or max heart rate is invalid.';
				break;
			case (122):
				$error .= 'The temperature unit is missing or invalid.';
				break;
			case (123):
				$error .= 'The workout effort is missing or invalid.';
				break;
			case (124):
				$error .= 'The workout quality is missing or invalid.';
				break;
			case (125):
				$error .= 'The interval type is missing or invalid.';
				break;
			case (126):
				$error .= 'The interval distance is missing or invalid.';
				break;
			case (127):
				$error .= 'The interval distance unit is missing or invalid.';
				break;
			case (128):
				$error .= 'The interval heart rate is missing or invalid.';
				break;
			case (129):
				$error .= 'The equipment ID is missing or invalid.';
				break;
			case (130):
				$error .= 'The brand ID is missing or invalid.';
				break;
			case (131):
				$error .= 'The model ID is missing or invalid.';
				break;
			case (132):
				$error .= 'The course ID is missing or invalid.';
				break;
			case (133):
				$error .= 'The course is missing or invalid.';
				break;
			case (134):
				$error .= 'The username is missing or invalid.';
				break;
			case (135):
				$error .= 'The specified username already exists.';
				break;
			case (136):
				$error .= 'The email is missing or invalid.';
				break;
			case (137):
				$error .= 'The specified email already exists.';
				break;
			case (138):
				$error .= 'The password is missing or invalid.';
				break;
			case (139):
				$error .= 'The temperature unit is missing or invalid.';
				break;
			case (140):
				$error .= 'The day of the week is missing or invalid.';
				break;
			case (141):
				$error .= 'The username is invalid.';
				break;
			case (142):
				$error .= 'The workout indicates it has extended data but the data cannot be located. (Please contact a runningahead administrator)';
				break;
			case (143):
				$error .= 'The workout has extended data but the packaging of the data failed. (Please contact a runningahead administrator)';
				break;
			case (143):
				$error .= 'The supplied external id is not associated with a user';
				break;
			default:
				$error .= 'An unknown error occured.';
		}

		throw new Exception('RunningAhead API: '.$error);
	}

	private function objToArray($object) {
		$array = array();
		
		if (is_object($object) || is_array($object))
			foreach ($object as $key => $value)
				$array[$key] = $this->objToArray($value);
		else
			$array = $object;

		return $array;
	}
	
	/**
	* createUser (Privileged Method) - Creates a new user account
	* @param $name Username
	* @param $email User's email address
	* @param $password User's password
	* @param $externalID User's ID. This is the ID that you supply to uniquely identifies the user. (Typically the user's ID from your system)
	* @return int 0 if success, -1 if not successful
	*/	
	function createUser($name, $email, $password, $externalID) {
		/* #CreateUser */
		$soapCall = 'CreateUser';

		$parameters = array(
							'sessionKey' => $this->SessionKey,
							'info' => array(
											'Name' => $name,
											'Email' => $email,
											'Password' => $password
											)
							);
							
		if (!empty($externalID))
			$parameters['info']['ExternalID'] = $externalID;
																	   
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => $parameters),
											// TODO: Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);
		
		// TODO: A bit nasty :/
		If (isset($return->CreateUserResult)) {
			$return = $return->CreateUserResult;
			if (!$return->Code)
				return 0;
			else
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}

	/**
	* getTokenAuthUrl (Privileged Method) - Gets an url that will login the user automatically to RA's web interface.
	* You must specify either user's email and password for RA OR their external ID.
	* @param $email User's email address
	* @param $password User's password
	* @param $externalID User's ID. This is the ID that you supply to uniquely identifies the user. (Typically the user's ID from your system)
	* @return String Authentication url, -1 if no matching courses were found
	*/	
	function getTokenAuthUrl($email, $password, $externalID) {
		/* #GetTokenAuthUrl */
		$soapCall = 'GetTokenAuthUrl';
		
		$filter = array();
		if (isset($email) && isset($password) && isset($externalID))
			$filter = array('Email' => $email, 'Password' => $password, 'ExternalID' => $externalID);
		else
			$this->throwError(105, $soapCall); // Must specify email AND password AND externalID
	
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'info' => $filter
																	   )
												 ),
											// TODO: Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);
		
		// TODO: A bit nasty :/
		If (isset($return->GetTokenAuthUrlResult)) {
			$return = $return->GetTokenAuthUrlResult;
			if (!$return->Code) {
				$return = $return->Data->Url;
				if (isset($return))
					return $this->objToArray($return);
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}

	/**
	* getCourse - Gets information on a specified course
	* @param String $courseID The ID of the course
	* @return Array Array containing matching courses, -1 if no matching courses were found
	*/
	function getCourse($courseID) {
		/* #GetCourse */
		$soapCall = 'GetCourse';
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'courseID' => $courseID
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);
											
		If (isset($return->GetCourseResult)) {
			$return = $return->GetCourseResult;
			if (!$return->Code) {
				$return = $return->Data->Course;
				if (isset($return))
					return $this->objToArray($return);
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}
	
	/**
	* getEquipment - Gets information on specified equipment
	* @param String $equipmentID The ID of the equipment
	* @return Array Array containing matching equipment, -1 if no matching courses were found
	*/
	function getEquipment($equipmentID) {
		/* #GetEquipment */
		$soapCall = 'GetEquipment';
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'equipmentID' => $equipmentID
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);
											
		If (isset($return->GetEquipmentResult)) {
			$return = $return->GetEquipmentResult;
			if (!$return->Code) {
				$return = $return->Data->Equipment;
				if (isset($return))
					return $this->objToArray($return);
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}
	
	/**
	 * getPreferences - Gets user's preferences
	 * @param String $preference [Optional] Specify a single preference to return
	 * @return String/Array Returns a string containing the preference setting if $preference was specified and found. Else returns an array containing the user's preferences.
	 */
	function getPreferences($preference = '') {
		if (empty($preferences) || !isset($preferences))
			return $this->userPreferences;
		
		if (isset($this->userPreferences[$preference]))
			return $this->userPreferences[$preference];
		
		return $this->userPreferences;
	}
	
	/**
	* getWeeklyStats - Gets weekly stats for specified date range
	* @param Date $beginDate Start date of weekly stats. Most date formats are accepted
	* @param Date $endDate [Optional] End date of weekly stats. Most date formats are accepted. Default value is current time & date.
	* @param int $activity [Optional] Activity types to return. Default value is 0 (All activities).
	* @param String $firstDayOfWeek [Optional] Specifie which day of the week is the 'first day'. Default value is Monday
	* @param bool $fullWeek [Optional] If $beginDate is not the first day of the week or $endDate is not the last day of the week, extend the dates to contain full week. Default value is True.
	* @return Array Array containing matching workouts, -1 if no matching workouts were found
	*/
	function getWeeklyStats($beginDate, $endDate = '', $activity = 0, $firstDayOfWeek = 'Monday', $fullWeek = True) {
		/* #GetWeeklyStats */
		$soapCall = 'GetWeeklyStats';
		
		$bDate = strtotime($beginDate);
		if (!$bDate)
			$bDate = time();
			
		$eDate = strtotime($endDate);
		if (!$eDate)
			$eDate = time();
		
		$beginDate = date("Y-m-d\TH:i:s", $bDate);
		$endDate = date("Y-m-d\TH:i:s", $eDate);
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'begin' => $beginDate,
																		'end' => $endDate,
																		'activity' => $activity,
																		'firstDayOfWeek' => $firstDayOfWeek,
																		'fullWeek' => $fullWeek
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);
											
		If (isset($return->GetWeeklyStatsResult)) {
			$return = $return->GetWeeklyStatsResult;
			if (!$return->Code) {
				$return = $return->Data->Stats->StatsData;
				if (isset($return))
					return $this->objToArray($return);
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}

	/**
	* getWorkout - Gets information on a specified workout
	* @param String $workoutID The ID of the workout
	* @return Array Array containing matching workout, -1 if no matching workout was found
	*/
	function getWorkout($workoutID) {
		/* #GetWorkout */
		$soapCall = 'GetWorkout';
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'workoutID' => $workoutID
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);
											
		If (isset($return->GetWorkoutResult)) {
			$return = $return->GetWorkoutResult;
			if (!$return->Code) {
				$return = $return->Data->Workout;
				if (isset($return))
					return $this->objToArray($return);
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}

	/**
	* getWorkoutData - Gets detailed information/measurements on a specified workout (Such as GPS data)
	* @param String $workoutID The ID of the workout
	* @param int $type File format of data, it must be set to 1
	* @param String $encoding The data's encoding method, please refer to API docs.
	* @return String matching workout in format specified, -1 if no matching workout was found
	*/
	function getWorkoutData($workoutID, $type = 'Gpx', $encoding = 'UTF8') {
		/* #GetWorkoutData */
		$soapCall = 'GetWorkoutData';
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'workoutID' => $workoutID,
																		'type' => $type,
																		'encoding' => $encoding
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);
											
		If (isset($return->GetWorkoutDataResult)) {
			$return = $return->GetWorkoutDataResult;
			if (!$return->Code) {
				$return = $return->Data->WorkoutData;
				if (isset($return))
					return $this->objToArray($return);
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}
		
	/**
	* listCourses - Lists user's courses
	* @param String $sortBy [Optional] Filter by which to sort results by, either 'ReferenceDate' or 'Alphabetical' (0 or 1 respectively), default value is 'ReferenceDate'
	* @param int $offset [Optional] The offset of which to start returning courses, default 0
	* @param int $limit [Optional] Limit of number of courses to return, max 100, default 100
	* @return Array Array containing matching courses, -1 if no matching courses were found
	*/
	function listCourses($sortBy = 'ReferenceDate', $offset = 0, $limit = 100) {
		/* #ListCourses */
		$soapCall = 'ListCourses';
		
		/* Replace enum int values with string literals */
		if ($sortBy === 0)
			$sortBy = 'ReferenceDate';
		elseif ($sortBy === 1)
			$sortBy = 'Alphabetical';
		
		/* Build filter array */
		$filter = array('SortBy' => $sortBy);
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'filter' => $filter,
																		'offset' => $offset,
																		'limit' => $limit
																	   )
												 ),
											// TODO: Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);
		
		// TODO: A bit nasty :/
		If (isset($return->ListCoursesResult)) {
			$return = $return->ListCoursesResult;
			if (!$return->Code) {
				$return = $return->Data->Courses->Course;
				if (isset($return))
					return $this->objToArray($return);
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}

	/**
	* listEquipment - Lists user's equipment
	* @param bool [Optional] $showRetired Whether to show 'retired' equipment or not, default value is True
	* @param int $eventTypeID [Optional] Only return equipment with specified event ID
	* @param int $offset [Optional] The offset of which to start returning equipment, default 0
	* @param int $limit [Optional] Limit of number of equipment to return, max 100, default 100
	* @return Array Array containing matching equipment, -1 if no matching equipment was found
	*/	
	function listEquipment($showRetired = true, $eventTypeID = 0, $offset = 0, $limit = 0) {
		/* #ListEquipment */
		$soapCall = 'ListEquipment';
		
		/* Build filter array */
		$filter = array('showRetired' => $showRetired);
		
		if ($eventTypeID != 0)
			$filter['eventTypeID'] = $eventTypeID;
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'filter' => $filter,
																		'offset' => $offset,
																		'limit' => $limit
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);

		// TODO: A bit nasty :/
		If (isset($return->ListEquipmentResult)) {
			$return = $return->ListEquipmentResult;
			if (!$return->Code) {
				$return = $return->Data->Equipment->Equipment;
				if (isset($return))
					return $this->objToArray($return);
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}
	
	/**
	* listEventTypes - Lists user's event types
	* @return Array Array containing event types, -1 if no event types were found
	*/	
	function listEventTypes() {
		/* #ListEventTypes */
		$soapCall = 'ListEventTypes';
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey
																	   )
												 ),
											// TODO: Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);
		
		// TODO: A bit nasty :/
		If (isset($return->ListEventTypesResult)) {
			$return = $return->ListEventTypesResult;
			if (!$return->Code) {
				$return = $return->Data->EventTypes->EventType;
				if (isset($return))
					return $this->objToArray($return);
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}

	/**
	* listWorkouts - Lists user's workouts
	* @param String/Array $fields A string or array of strings containing the name of the data fields you wish to be returned. Please refer to the API docs for a list of data fields. (An array is only required for more than one field)
	* @param int $offset [Optional] The offset of which to start returning equipment, default 0
	* @param int $limit [Optional] Limit of number of workouts to return, max 100, default 100
	* @return Array Array containing workouts, -1 if no matching workouts were found
	*/
	function listWorkouts($fields, $offset = 0, $limit = 0) {
		/* #ListWorkouts */
		$soapCall = 'ListWorkouts';

		/* Some basic error checking */
		if (empty($fields))
			$this->throwError(106, $soapCall);
		
		/* Build filter array */
		$filter = array();
		if (is_array($fields))
			$filter['Fields']['DataFieldID'] = $fields;
		else
			$filter = array('Fields' =>
										array('DataFieldID' => $fields)
							);
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'filter' => $filter,
																		'offset' => $offset,
																		'limit' => $limit
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);

		If (isset($return->ListWorkoutsResult)) {
			$return = $return->ListWorkoutsResult;
			if (!$return->Code) {
				$return = $return->Data->Workouts->Workout;
				if (isset($return))
					return $this->objToArray($return);
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}

	/**
	* importWorkouts - Imports workout from specified data
	* @param String $data The contents of the workout data.
	* @param String $type The data type.
	* @param String $encoding The encoding type. Please refer to API docs.
	* @return String New workout ID, -1 if failed.
	*/
	function importWorkouts($data, $type = 'Gpx', $encoding = '0x01') {
		/* #ImportWorkouts */
		$soapCall = 'ImportWorkouts';
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'type' => $type,
																		'encoding' => $encoding,
																		'data' => $data
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);
											
		If (isset($return->ImportWorkoutsResult)) {
			$return = $return->ImportWorkoutsResult;
			if (!$return->Code) {
				$return = $return->Data->WorkoutIds->guid;
				if (isset($return))
					return $this->objToArray($return);
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}

	/**
	* saveCourse - Saves a new course.
	* @param int $distance Course distance.
	* @param String/int $distanceUnit Course distance unit, e.g. kilometer.
	* @param String $name Course name.
	* @param String $notes [Optional] Course notes.
	* @param Surface $surface surface of course. Use {@link createSurfaceType() createSurfaceType()}.
	* @return String Saved course ID, -1 if failed.
	*/
	function saveCourse($distance, $distanceUnit, $name, $notes = '', $surface = NULL) {
		/* #SaveCourse */
		$soapCall = 'SaveCourse';
		
		/* If they didn't pass a number, just error */
		if (!is_numeric($distance))
			$this->throwError(106, $soapCall);
			
		/* Allow numerical values */
		if (is_numeric($distanceUnit)) {
			switch ($distanceUnit) {
				case 0:
					$distanceUnit = 'Kilometer';
					break;
				case 1:
					$distanceUnit = 'Mile';
					break;
				case 2:
					$distanceUnit = 'Meter';
					break;
				case 3:
					$distanceUnit = 'Yard';
					break;
				default:
					$distanceUnit = 'Unknown';
					break;
			}
		} else {
			/* Is case senstive, so force correct case! */
			$distanceUnit = ucfirst(strtolower($distanceUnit));
		}
		
		/* Build course array */
		$course = array(
						'Name' => $name,
						'Distance' => $distance,
						'DistanceUnit' => $distanceUnit,
						'Notes' => $notes,
						);
		
		if ($surface == NULL)
			$course['Surfaces'] = $this->createSurfaceType();
		else
			$course['Surfaces'] = $surface;
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'course' => $course
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);

		If (isset($return->SaveCourseResult)) {
			$return = $return->SaveCourseResult;
			if (!$return->Code) {
				$return = $return->Data->CourseID;
				if (isset($return))
					return $return;
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}

	/**
	* saveEquipment - Save new equipment
	* @param String $equipmentID Equipment ID.
	* @param String $brandName Equipment brand name.
	* @param int $brandID Equipment brand ID.
	* @param String $modelName Equipment model name.
	* @param String $modelID Equipment model ID.
	* @param String $serial Equipment serial number.
	* @param String $eventTypeID ID of event types this equipment will be used for, e.g. 10 for running. Please see API docs for more values.
	* @param int $price Purchase price of equipment.
	* @param int $initialDistance Initial distance equipment has done before entry.
	* @param int $initialDistance Total distance equipment has done.
	* @param Date $purchaseDate Date of equipment purchase.
	* @param Date $retireDate [Optional] Date of retirement for equipment. If left unset, equipment is made active (in-use).
	* @param String $notes [Optional] Any extra notes about equipment.
	* @return String Saved equipment ID, -1 if failed.
	*/
	function saveEquipment($equipmentID, $brandName, $brandID, $modelName, $modelID, $serial, $eventTypeID, $price, $initialDistance, $distance, $purchaseDate, $retireDate = '', $notes = '') {
		/* #SaveEquipment */
		$soapCall = 'SaveEquipment';
		
		/* If they didn't pass a number, just error */
		if (!is_numeric($price) || empty($equipmentID))
			$this->throwError(106, $soapCall);
			
		/* Convert dates to correct format */
		$pDate = strtotime($purchaseDate);
		if (!$pDate)
			$pDate = time();
		
		$purchaseDate = date("Y-m-d", $pDate);
		
		if (isset($retireDate) && !empty($retireDate)) {
			$rDate = strtotime($retireDate);
			if (!$rDate)
				$rDate = time();
		
			$retireDate = date("Y-m-d", $rDate);
		}
		
		/* Build equipment array */
		$equipment = array(
							'ID' => $equipmentID,
							'EventTypeID' => $eventTypeID,
							'BrandName' => $brandName,
							'ModelName' => $modelName,
							'Serial' => $serial,
							'Price' => $price,
							'InitialDistance' => $initialDistance,
							'PurchaseDate' => $purchaseDate,
							'Notes' => $notes
						   );

		if (!empty($distance))
			$equipment['Distance'] = $distance;
						   
		if (!empty($brandID))
			$equipment['BrandID'] = $brandID;
			
		if (!empty($modelID))
			$equipment['ModelID'] = $modelID;
			
		if (!empty($retireDate))
			$equipment['RetireDate'] = $retireDate;
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'equipment' => $equipment
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);

		If (isset($return->SaveEquipmentResult)) {
			$return = $return->SaveEquipmentResult;
			if (!$return->Code) {
				$return = $return->Data->EquipmentID;
				if (isset($return))
					return $return;
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}

	/**
	* savePreferences - Save user preferences. 
	* You need only set the prefences you wish to change. Please see API docs for setting values.
	* @param String/int $distanceUnit user's default distance unit, e.g. kilometer or 0.
	* @param String/int $weightUnit user's default weight unit, e.g. Pounds or 0.
	* @param String/int $temperatureUnit user's default temperature unit, e.g. Celsius or 0.
	* @param String/int $firstDayOfWeek user's default first day of the week, e.g. Monday or 1.
	* @return int 0 if successful, -1 if failed
	*/
	function savePreferences($distanceUnit = '', $weightUnit = '', $temperatureUnit = '', $firstDayOfWeek = '') {
		/* #SavePreferences */
		$soapCall = 'SavePreferences';
		
		/* If they didn't pass a number, just error */
		if (empty($distanceUnit) && empty($weightUnit) && empty($temperatureUnit) && empty($firstDayOfWeek))
			$this->throwError(106, $soapCall);
			
		$preferences = array();
		$oldPreferences = $this->getPreferences();
		
		if (!empty($distanceUnit)) {
			/* Allow numerical values */
			if (is_numeric($distanceUnit)) {
				switch ($distanceUnit) {
					case 0:
						$distanceUnit = 'Kilometer';
						break;
					case 1:
						$distanceUnit = 'Mile';
						break;
					case 2:
						$distanceUnit = 'Meter';
						break;
					case 3:
						$distanceUnit = 'Yard';
						break;
					default:
						$distanceUnit = 'Unknown';
						break;
				}
			} else {
				/* Is case senstive, so force correct case! */
				$distanceUnit = ucfirst(strtolower($distanceUnit));
			}
			
			$preferences['DistanceUnit'] = $distanceUnit;
			$this->userPreferences['DistanceUnit'] = $distanceUnit;
		} else {
			$preferences['DistanceUnit'] = $oldPreferences['DistanceUnit'];
		}
		
		if (!empty($weightUnit)) {
			/* Allow numerical values */
			if (is_numeric($weightUnit)) {
				switch ($weightUnit) {
					case 0:
						$weightUnit = 'Pound';
						break;
					case 1:
						$weightUnit = 'Kilogram';
						break;
					default:
						$weightUnit = 'Unknown';
						break;
				}
			} else {
				/* Is case senstive, so force correct case! */
				$weightUnit = ucfirst(strtolower($weightUnit));
			}
			
			$preferences['WeightUnit'] = $weightUnit;
			$this->userPreferences['WeightUnit'] = $weightUnit;
		} else {
			$preferences['WeightUnit'] = $oldPreferences['WeightUnit'];
		}
		
		if (!empty($temperatureUnit)) {
			/* Allow numerical values */
			if (is_numeric($temperatureUnit)) {
				switch ($temperatureUnit) {
					case 0:
						$temperatureUnit = 'Celsius';
						break;
					case 1:
						$temperatureUnit = 'Fahrenheit';
						break;
					default:
						$temperatureUnit = 'Unknown';
						break;
				}
			} else {
				/* Is case senstive, so force correct case! */
				$temperatureUnit = ucfirst(strtolower($temperatureUnit));
			}
			
			$preferences['TemperatureUnit'] = $temperatureUnit;
			$this->userPreferences['TemperatureUnit'] = $temperatureUnit;
		} else {
			$preferences['TemperatureUnit'] = $oldPreferences['TemperatureUnit'];
		}
		
		if (!empty($firstDayOfWeek)) {
			/* Allow numerical values */
			if (is_numeric($firstDayOfWeek)) {
				switch ($firstDayOfWeek) {
					case 1:
						$firstDayOfWeek = 'Monday';
						break;
					case 7:
						$firstDayOfWeek = 'Sunday';
						break;
					default:
						$firstDayOfWeek = 'Monday';
						break;
				}
			} else {
				/* Is case senstive, so force correct case! */
				$firstDayOfWeek = ucfirst(strtolower($firstDayOfWeek));
			}
			
			$preferences['FirstDayOfWeek'] = $firstDayOfWeek;
			$this->userPreferences['FirstDayOfWeek'] = $firstDayOfWeek;
		} else {
			$preferences['FirstDayOfWeek'] = $oldPreferences['FirstDayOfWeek'];
		}
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'preferences' => $preferences
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);

		If (isset($return->SavePreferencesResult)) {
			$return = $return->SavePreferencesResult;
			if (!$return->Code) {
				return 0;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}

	/**
	* saveWorkout - Saves a new workout. 
	* You must specify either a distance or a duration. You can specify both, but you do not have to.
	* @param int $workoutID [Optional] ID of workout you are modifying. Leave blank to create a new workout.
	* @param Date $date [Optional] Date of workout. Default value is today's date
	* @param Time $timeOfDay [Optional] Time of workout.
	* @param String $eventType Event type, e.g. Run
	* @param int $eventTypeID Event type ID, e.g. 10 for run
	* @param String $eventSubType Event sub type e.g. Tempo
	* @param int $eventSubTypeID Event sub type ID e.g. 1 for default
	* @param String $courseName [Optional] Name of course used for workout.
	* @param int $courseID [Optional] ID of course used for workout.
	* @param int $distance Workout distance.
	* @param String/int $distanceUnit Workout distance unit of measurement, e.g. Kilometer or 0.
	* @param int $duration Workout duration.
	* @param String $equipmentName [Optional] Name of equipment used for workout.
	* @param int $equipmentID [Optional] ID of equipment used for workout.
	* @param int $weight [Optional] User's weight.
	* @param String/int $weightUnit [Optional] Unit of weight measurement, e.g. Pound or 0.
	* @param int $restHR [Optional] Workout resting heart rate.
	* @param int $avgHR [Optional] Workout average heart rate.
	* @param int $maxHR [Optional] Workout maximum heart rate.
	* @param int $temperature [Optional] Workout temperature.
	* @param String/int $temperatureUnit [Optional] Unit of temperature measurement, e.g. Celcius or 0.
	* @param String $notes [Optional] Workout notes.
	* @param Weather $weatherConditions [Optional] Workout weather conditions. @see createWeatherType()
	* @param int $fieldPlacement [Optional] field placement.
	* @param int $fieldSize [Optional] Field Size.
	* @param int $groupMinAge [Optional] Minimum group age.
	* @param int $groupMaxAge [Optional] Maximum group age.
	* @param int $groupPlacement [Optional] Group placement.
	* @param int $groupSize [Optional] Group size.
	* @param int $genderPlacement [Optional] Gender placement.
	* @param int $genderSize [Optional] Gender size.
	* @param int $quality [Optional] Workout quality rating between 1 and 10 (inclusive).
	* @param int $effort [Optional] Workout effort rating between 1 and 10 (inclusive).
	* @param Interval $intervalSet [Optional] Set of workout intervals. Use {@link createIntervalSet() createIntervalSet()}.
	*/
	function saveWorkout($workoutID, $date, $timeOfDay, $eventType, $eventTypeID, $eventSubType, $eventSubTypeID, $courseName, $courseID, $distance, $distanceUnit,
						 $duration, $equipmentName, $equipmentID, $weight, $weightUnit, $restHR, $avgHR, $maxHR, $temperature, $temperatureUnit,
						 $notes, $weatherConditions, $fieldPlacement, $fieldSize, $groupMinAge, $groupMaxAge, $groupPlacement, $groupSize, $genderPlacement,
						 $genderSize, $quality, $effort, $intervalSet) {
		
		/* #SaveWorkout */
		$soapCall = 'SaveWorkout';
		
		$workout = array();
		
		if (!empty($workoutID))
			$workout['ID'] = $workoutID;
		
		/* Convert dates to correct format */
		$dDate = strtotime($date);
		if (!$dDate)
			$dDate = time();
		
		$workout['Date'] = date("Y-m-d", $dDate);
		
		if (!empty($timeOfDay))
			$workout['TimeOfDay'] = $timeOfDay;
		
		$workout['EventType'] = $eventType;
		$workout['EventTypeID'] = $eventTypeID;
		$workout['EventSubType'] = $eventSubType;
		$workout['EventSubTypeID'] = $eventSubTypeID;
		
		if (!empty($courseName))
			$workout['CourseName'] = $courseName;
			
		if (!empty($courseID))
			$workout['CourseID'] = $courseID;
		
		if (!empty($distance))
			$workout['Distance'] = $distance;
		
		if (!empty($distance) && isset($distanceUnit)) {
			if (is_numeric($distanceUnit)) {
				switch ($distanceUnit) {
					case 0:
						$workout['DistanceUnit'] = 'Kilometer';
						break;
					case 1:
						$workout['DistanceUnit'] = 'Mile';
						break;
					case 2:
						$workout['DistanceUnit'] = 'Meter';
						break;
					case 3:
						$workout['DistanceUnit'] = 'Yard';
						break;
					default:
						$workout['DistanceUnit'] = 'Unknown';
						break;
				}
			} else {
				/* Is case senstive, so force correct case! */
				$workout['DistanceUnit'] = ucfirst(strtolower($distanceUnit));
			}
		}
			
		if (!empty($Duration))
			$workout['Duration'] = $duration;
			
		if (!empty($equipmentName))
			$workout['EquipmentName'] = $equipmentName;
		
		if (!empty($equipmentID))
			$workout['EquipmentID'] = $equipmentID;
		
		if (!empty($weight))
			$workout['Weight'] = $weight;
		
		if (!empty($weight) && isset($weightUnit))
			$workout['WeightUnit'] = $weightUnit;
		
		if (!empty($restHR))
			$workout['RestHR'] = $restHR;
		
		if (!empty($avgHR))
			$workout['AvgHR'] = $avgHR;
			
		if (!empty($maxHR))
			$workout['MaxHR'] = $maxHR;
			
		if (!empty($temperature))
			$workout['Temperature'] = $temperature;
		
		if (!empty($temperature) && isset($temperatureUnit))
			$workout['TemperatureUnit'] = $temperatureUnit;
			
		if (!empty($notes))
			$workout['Notes'] = $notes;
		
		if (!empty($weather))
			$workout['WeatherConditions'] = $weather;

		if (!empty($fieldPlacement))
			$workout['FieldPlacement'] = $fieldPlacement;
		
		if (!empty($fieldSize))
			$workout['FieldSize'] = $fieldSize;
			
		if (!empty($groupMinAge))
			$workout['GroupMinAge'] = $groupMinAge;
		
		if (!empty($groupMaxAge))
			$workout['GroupMaxAge'] = $groupMaxAge;
		
		if (!empty($groupPlacement))
			$workout['GroupPlacement'] = $groupPlacement;
		
		if (!empty($groupSize))
			$workout['GroupSize'] = $groupSize;
			
		if (!empty($genderPlacement))
			$workout['GenderPlacement'] = $genderPlacement;
			
		if (!empty($genderSize))
			$workout['GenderSize'] = $genderSize;
			
		if (!empty($quality))
			$workout['Quality'] = $quality;
		
		if (!empty($effort))
			$workout['Effort'] = $effort;
		
		if (!empty($url))
			$workout['Url'] = $url;
			
		if (!empty($intervalSet)) {
			$workout['IntervalSet'] = $intervalSet;
			$workout['HasDetailedData'] = true;
		} else {
			$workout['HasDetailedData'] = false;
		}
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'workout' => $workout
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);
											
		If (isset($return->SaveWorkoutResult)) {
			$return = $return->SaveWorkoutResult;
			if (!$return->Code) {
				$return = $return->Data->WorkoutID;
				if (!empty($return))
					return $return;
				return -1;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}
	
	/**
	* impersonateUser - Impersonates a user (Required to be called before most other functions)
	* @param String $email Email address of user account
	* @param String $password Password of user account
	* @return int 0 if successful, -1 if failed
	*/
	function impersonateUser($email, $password) {
	
		$signature = $this->AppSecret.$this->SessionKey.$email.$password;
		$signature = md5($signature);
		
		/* #ImpersonateUser */
		$soapCall = 'ImpersonateUser';
		
		$return = $this->Client->__soapCall($soapCall,
											array('parameters' => array(
																		'sessionKey' => $this->SessionKey,
																		'email' => $email,
																		'password' => $password,
																		'signature' => $signature
																	   )
												 ),
											// Hack fix? PHP prefixes call names with a # ...
											array('soapaction' => $this->SoapAction.$soapCall)
											);
											
		If (isset($return->ImpersonateUserResult)) {
			$return = $return->ImpersonateUserResult;
			if (!$return->Code) {
				$this->userPreferences = $this->objToArray($return->Data->UserPreferences);
				return 0;
			} else {
				$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
			}
		} else {
			$this->throwError(isset($return->Code) ? $return->Code : 0, $soapCall);
		}
		
		return -1;
	}

	/**
	* createWeatherType - Creates a weather object
	* This function aims to reduce list of parameters in some function calls.
	* @param bool $clear Clear or not. Default value false.
	* @param bool $partlyCloudy Partly cloudy or not. Default value false.
	* @param bool $overcast Overcast or not. Default value false.
	* @param bool $rain Raining or not. Default value false.
	* @param bool $snow Snowing or not. Default value false.
	* @param bool $windy Windy or not. Default value false.
	* @param bool $humid Humid or not. Default value false.
	*/
	function createWeatherType($clear = false, $partlyCloudy = false, $overcast = false, $rain = false, $snow = false, $windy = false, $humid = false) {
		$weather = array();
		
		if ($clear)
			$weather['Clear'] = true;
		if ($partlyCloudy)
			$weather['PartlyCloudy'] = true;
		if ($overcast)
			$weather['Overcast'] = true;
		if ($rain)
			$weather['Rain'] = true;
		if ($snow)
			$weather['Snow'] = true;
		if ($windy)
			$weather['Windy'] = true;
		if ($humid)
			$weather['Humid'] = true;
	
		return $weather;
	}

	/**
	* createSurfaceType - Creates an surface object. 
	* This function aims to reduce list of parameters in some function calls.
	* @param bool $asphalt Course is asphalt or not. Default value false.
	* @param bool $concrete Course is concrete or not. Default value false.
	* @param bool $grass Course is grass or not. Default value false.
	* @param bool $trail Course is trail or not. Default value false.
	* @param bool $track Course is track or not. Default value false.
	* @param bool $treadmill Course is treadmill or not. Default value false.
	* @return Surface
	*/
	function createSurfaceType($asphalt = false, $concrete = false, $grass = false, $trail = false, $track = false, $treadmill = false) {
		return array(
					 'Asphalt' => $asphalt,
					 'Concrete' => $concrete,
					 'Grass' => $grass,
					 'Trail' => $trail,
					 'Track' => $track,
					 'Treadmill' => $treadmill
					);
	}
	
	/**
	* createIntervalSet - creates a set of intervals. 
	* The first parameter specifies the interval name. All proceeding parameters are in blocks of 7 to specify details of each interval.
	* @param int $distance Interval distance.
	* @param String/int $distanceUnit Interval distance unit, e.g. kilometer or 0.
	* @param int $duration Interval duration.
	* @param int $avgHR Average heart rate for interval.
	* @param int $maxHR Max heart rate for interval.
	* @param String $notes Interval notes
	* @param int $type Interval type, e.g. Recovery or 1
	* @return IntervalSet
	*/
	function createIntervalSet($name) {
		$ints = array();
		$iArgs = func_num_args();
		$aArgs = func_get_args();
		
		$ints['name'] = $name;
		
		for ($i = 0; $i < $iArgs; $i++) {
			$intNum = (int) (($i - 1) / 7);
			
		    switch (($i - 1) % 7) {
				case (0):
					$ints['Interval'][$intNum]['Distance'] = $aArgs[$i];
					break;
				case (1):
					if ($aArgs[$i] == 0)
						$ints['Interval'][$intNum]['DistanceUnit'] = 'Kilometer';
					elseif ($aArgs[$i] == 1)
						$ints['Interval'][$intNum]['DistanceUnit'] = 'Mile';
					elseif ($aArgs[$i] == 2)
						$ints['Interval'][$intNum]['DistanceUnit'] = 'Meter';
					elseif ($aArgs[$i] == 3)
						$ints['Interval'][$intNum]['DistanceUnit'] = 'Yard';
					elseif (is_numeric($aArgs[$i]))
						$ints['Interval'][$intNum]['DistanceUnit'] = 'Unknown';
					else
						$ints['Interval'][$intNum]['DistanceUnit'] = ucfirst(strtolower($aArgs[$i]));

					break;
				case (2):
					$ints['Interval'][$intNum]['Duration'] = $aArgs[$i];
					break;
				case (3):
					$ints['Interval'][$intNum]['AvgHR'] = $aArgs[$i];
					break;
				case (4):
					$ints['Interval'][$intNum]['MaxHR'] = $aArgs[$i];
					break;
				case (5):
					$ints['Interval'][$intNum]['Notes'] = $aArgs[$i];
					break;
				case (6):
					if ($aArgs[$i] == 0)
						$ints['Interval'][$intNum]['Type'] = 'Interval';
					elseif ($aArgs[$i] == 1)
						$ints['Interval'][$intNum]['Type'] = 'Recovery';
					elseif ($aArgs[$i] == 2)
						$ints['Interval'][$intNum]['Type'] = 'Rest';
					else
						$ints['Interval'][$intNum]['Type'] = ucfirst(strtolower($aArgs[$i]));
						
					break;
			}
		}
		
		return $ints;
	}
}
?>